/**
 * JavaDistiller Refactoring API.
 * <p>
 * 
 * @author sleroy
 * @version $LastChangedRevision: 1833 $ $LastChangedDate: 2010-07-07 13:50:55 +0200 (mer., 07 juil. 2010) $
 * @since 27 mars 2009
 * @copyright Copyright (C) 2008-2009 IRISA/INRIA Property.
 */
package com.insta.formation;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

/**
 * This utility class provides some methods to manipulate XML representations.
 * 
 * @copyright Copyright (c) 2008 INRIA/Irisa
 */
public final class XmlUtils {

	/**
	 * This field describes
	 */
	private static final String EXCEPTION_HAPPENED = "Exception happened "; //$NON-NLS-1$

	/**
	 * This method marshalles a structure into a xml.
	 * 
	 * @param _object
	 *            the object, root of the XML
	 * @param _outputFile
	 *            the output file
	 * @throws JAXBException
	 */
	public static void marshallXML(final Object _object,
			final java.io.File _outputFile) throws JAXBException {

		String packageName;
		if (_object instanceof JAXBElement) {
			@SuppressWarnings("rawtypes")
			final Object value = ((JAXBElement) _object).getValue();
			if (value == null) {
				System.err.println("Cannot guess which package name is it."); //$NON-NLS-1$
				return;
			}
			packageName = value.getClass().getPackage().getName();
		} else {
			packageName = _object.getClass().getPackage().getName();
		}
		marshallXML(_object, _outputFile, packageName);
	}

	/**
	 * This method marshalles a structure into a xml.
	 * 
	 * @param _object
	 *            the object, root of the XML
	 * @param _outputFile
	 *            the output file
	 * @param _packageName
	 *            the name of the package
	 * @throws JAXBException
	 */
	public static void marshallXML(final Object _object,
			final java.io.File _outputFile, final String _packageName)
			throws JAXBException {

		final JAXBContext context = JAXBContext.newInstance(_packageName);
		final Marshaller createMarshaller = context.createMarshaller();
		createMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
				Boolean.TRUE);
		createMarshaller.marshal(_object, _outputFile);
	}

	/**
	 * This method unmarshall an xml file from a definition.
	 * 
	 * @param <T>
	 *            the type of element expected in return.
	 * @param _stream
	 *            the intput stream
	 * @param _objectFactory
	 *            the package definition of the xml schema
	 * @return the root element or null in case of error.
	 * @since 16 juin 2010
	 * @author sleroy
	 */
	@SuppressWarnings("unchecked")
	public static <T> T unmarshallXML(final InputStream _stream,
			final Class<?> _objectFactory) {

		if (_stream == null) {
			System.err.println("No information received."); //$NON-NLS-1$
			return null;
		}
		T res = null;
		final ClassLoader currentCL = Thread.currentThread()
				.getContextClassLoader();
		try {
			final ClassLoader classLoader = _objectFactory.getClassLoader();
			Thread.currentThread().setContextClassLoader(classLoader);
			final JAXBContext jc = JAXBContext.newInstance(_objectFactory
					.getPackage().getName());
			final Unmarshaller unmarshaller = jc.createUnmarshaller();
			final Object unmarshal = unmarshaller.unmarshal(_stream);
			if (unmarshal instanceof JAXBElement) {
				res = ((JAXBElement<T>) unmarshal).getValue();
			} else {
				res = (T) unmarshal;
			}
		} catch (final Throwable e) {
			/* Produces the exception description in the log. */
			System.err.println(e);
			e.printStackTrace();
			res = null;
		} finally {
			Thread.currentThread().setContextClassLoader(currentCL);
			try {
				_stream.close();
			} catch (final Exception e) {
				System.err.println(e);
				e.printStackTrace();
			}
		}
		return res;
	}

	/**
	 * This method unmarshall an xml file from a definition.
	 * 
	 * @param <T>
	 *            the type of element expected in return.
	 * @param _file
	 *            the file
	 * @param _objectFactory
	 *            the package definition of the xml schema
	 * @return the root element or null in case of error.
	 * @since 16 juin 2010
	 * @author sleroy
	 */
	@SuppressWarnings("unchecked")
	public static <T> T unmarshallXML(final URL _file,
			final Class<?> _objectFactory) {

		if (_file == null) {
			return null;
		}
		T res = null;
		try {
			res = (T) unmarshallXML(_file.openStream(), _objectFactory);
		} catch (final IOException e) {
			System.err.println(EXCEPTION_HAPPENED);
			e.printStackTrace();
		}

		return res;
	}

	/**
	 * Private Deprecated Constructor. (Utility class)
	 */
	@Deprecated
	private XmlUtils() {

		// Private Constructor
	}
}
